package com.yxsk.relay.job.admin.core.router.container;

import com.yxsk.relay.job.admin.core.router.endpoint.EndpointRouterInfo;
import com.yxsk.relay.job.component.common.vo.Endpoint;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @Author 11376
 * @CreaTime 2019/6/16 0:39
 * @Description
 */
@Slf4j
public class EndpointCycleList {

    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    // key: endpoint.host:endpoint.port, value: element
    private Map<String, Element> elementMap = new ConcurrentHashMap<>();
    // 头部元素
    private Element head = null;

    // 读取当前的元素
    private volatile Element readCurrentE = null;

    private volatile int size = 0;

    public EndpointRouterInfo nextEndpoint() {
        if (this.readCurrentE == null) {
            return null;
        }
        this.readWriteLock.writeLock().lock();
        try {
            Element next = readCurrentE.next;
            if (next == null) {
                return readCurrentE.info;
            }
            // 读取当前元素信息
            EndpointRouterInfo readInfo = this.readCurrentE.info;
            // 切换下一个元素
            this.readCurrentE = next;
            return readInfo;
        } finally {
            this.readWriteLock.writeLock().unlock();
        }
    }

    public void addEndpoint(EndpointRouterInfo endpointRouterInfo) {
        this.readWriteLock.writeLock().lock();
        try {
            if (this.elementMap.get(this.getKey(endpointRouterInfo.getEndpoint().getHost(), endpointRouterInfo.getEndpoint().getPort())) != null) {
                // 已存在该元素
                return;
            }
            Element element = new Element(endpointRouterInfo, null, null);
            if (this.head == null) {
                this.head = element;
                // 重置读取元素
                this.readCurrentE = element;
            } else if (this.head.next == null) {
                // 当前元素表仅有一个 head
                // 添加元素形成闭环
                this.head.next = element;
                this.head.previous = element;

                element.next = this.head;
                element.previous = this.head;
            } else {
                // 链表存在两个以上元素
                // head > e2  >> head > e2 > e3
                Element e2 = this.head.previous;
                e2.next = element;
                this.head.previous = element;
                element.previous = e2;
                element.next = this.head;
            }
            ++this.size;
            Endpoint endpoint = endpointRouterInfo.getEndpoint();
            this.elementMap.put(getKey(endpoint.getHost(), endpoint.getPort()), element);
        } finally {
            this.readWriteLock.writeLock().unlock();
        }
    }

    public void remove(String host, Integer port) {
        this.readWriteLock.writeLock().lock();
        try {
            if (this.elementMap.get(getKey(host, port)) == null) {
                return;
            }
            Element element = this.elementMap.remove(getKey(host, port));
            if (element != null) {
                if (element == this.head) {
                    if (this.size == 1) {
                        // 仅一个元素
                        this.head = null;
                        this.readCurrentE = null;
                    } else if (this.size == 2) {
                        // 存在两个元素, 且删除的是头元素
                        Element e2 = this.head.next;

                        e2.previous = null;
                        e2.next = null;
                        this.head = e2;

                        this.readCurrentE = e2;
                    } else {
                        // 其他情况
                        Element lastE = this.head.previous;

                        // 重置 head 的环
                        this.head = this.head.next;
                        this.head.previous = lastE;
                        lastE.next = this.head;

                        if (this.readCurrentE == element) {
                            // 元素下移
                            this.readCurrentE = this.readCurrentE.next;
                        }
                    }
                } else if (this.size == 2 && this.head != element) {
                    // 两个元素，但不是删除的此元素
                    this.head.next = null;
                    this.head.previous = null;

                    if (this.readCurrentE == element) {
                        this.readCurrentE = this.head;
                    }
                } else {
                    // 上一个元素的下一个元素为该元素的下一个元素
                    // e1 > e2 > e3   >>>>>>  e1 > e3
                    Element e3 = element.next;
                    element.previous.next = e3;
                    e3.previous = element.previous;

                    if (element == readCurrentE) {
                        // 当前读取元素为删除元素, 读取元素下移一个游标
                        this.readCurrentE = e3;
                    }
                }
                --this.size;
            }
        } finally {
            this.readWriteLock.writeLock().unlock();
        }
    }

    private String getKey(String host, Integer port) {
        return host.concat(":").concat(port.toString());
    }

    public List<EndpointRouterInfo> getList() {
        if (this.head == null) {
            return Collections.emptyList();
        }
        this.readWriteLock.readLock().lock();
        try {
            List<EndpointRouterInfo> list = new ArrayList<>();
            Element next = null;
            while (true) {
                if (next == null) {
                    list.add(head.info);
                    if (head.next == null) {
                        break;
                    }
                    next = head.next;
                } else {
                    list.add(next.info);
                    next = next.next;
                    if (next == head) {
                        // 查找结束
                        break;
                    }
                }
            }
            return list;
        } finally {
            this.readWriteLock.readLock().unlock();
        }
    }

    public int size() {
        return this.size;
    }

    @AllArgsConstructor
    private class Element {
        // 节点元素
        EndpointRouterInfo info;
        // 上一个元素
        Element previous;
        // 下一个元素
        Element next;
    }

}
